package soulkun.library.mvvm.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableArrayList
import androidx.databinding.ObservableList
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView

/**
 * 封装DataBinding和RecyclerView结合的BaseAdapter
 * listChangedCallback允许为null，则在子adapter中自己实现对应的notify方法
 */
abstract class BaseDataBindingRecyclerViewAdapter<E : Any>(
    protected val context: Context,
    protected val dataList: ObservableArrayList<E>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        const val TAG = "BaseDataBindingAdapter"
        const val contentViewType = 0
        const val headViewType = 1
        const val footViewType = 2
        const val emptyViewType = 3
    }

    inner class ListChangedCallback<E : Any> :
        ObservableList.OnListChangedCallback<ObservableArrayList<E>>() {

        override fun onChanged(sender: ObservableArrayList<E>?) {
            notifyDataSetChanged()
            dataChangedListener()
        }

        override fun onItemRangeChanged(
            sender: ObservableArrayList<E>?,
            positionStart: Int,
            itemCount: Int
        ) {
            notifyItemRangeChanged(
                positionStart + if (headLayoutIdRes != null) 1 else 0,
                itemCount
            )
            dataChangedListener()
        }

        override fun onItemRangeInserted(
            sender: ObservableArrayList<E>?,
            positionStart: Int,
            itemCount: Int
        ) {
            if (positionStart == 0) {
                notifyDataSetChanged()
            }else{
                notifyItemRangeInserted(
                    positionStart + if (headLayoutIdRes != null) 1 else 0,
                    itemCount
                )
            }
            dataChangedListener()
        }

        override fun onItemRangeMoved(
            sender: ObservableArrayList<E>?,
            fromPosition: Int,
            toPosition: Int,
            itemCount: Int
        ) {
            if (itemCount == 1) {
                notifyItemMoved(fromPosition, toPosition)
            } else {
                notifyDataSetChanged()
            }
            dataChangedListener()
        }

        override fun onItemRangeRemoved(
            sender: ObservableArrayList<E>?,
            positionStart: Int,
            itemCount: Int
        ) {
            if (positionStart == 0 && dataList.size == 0) {
                notifyDataSetChanged()
            } else {
                if (itemCount == 1) {
                    notifyItemRemoved(positionStart)
                } else {
                    notifyItemRangeRemoved(
                        positionStart,
                        itemCount
                    )
                }
            }
            dataChangedListener()
        }
    }

    //使用ItemDecoration时注意在数据变化后调用RecyclerView的invalidateItemDecorations()方法
    var dataChangedListener = {

    }

    //设置数据变化的监听
    private val listChangedCallback = ListChangedCallback<E>()

    //以下三种布局以及对应的监听器
    var headLayoutIdRes: Int? = null
        private set
    private var headCreateBindingListener: ((ViewDataBinding) -> Unit)? = null
    private var headBindViewListener: ((ViewDataBinding) -> Unit)? = null
    var footLayoutIdRes: Int? = null
        private set
    private var footCreateBindingListener: ((ViewDataBinding) -> Unit)? = null
    private var footBindViewListener: ((ViewDataBinding) -> Unit)? = null
    var emptyLayoutIdRes: Int? = null
        private set
    private var emptyCreateBindingListener: ((ViewDataBinding) -> Unit)? = null
    private var emptyBindViewListener: ((ViewDataBinding) -> Unit)? = null

    //必须获取内容的布局ID
    abstract fun getContentLayoutResId(): Int

    //必须设置创建时的监听
    abstract fun setContentViewHolderCreateListener(binding: ViewDataBinding)

    //必须创建绑定视图时的监听
    abstract fun setContentViewHolderBindListener(binding: ViewDataBinding, dataPosition: Int)

    //必须创建解绑视图时的数据清除
//    abstract fun setContentViewHolderRecycleListener()

    //多样化布局设置
    fun setHeadLayout(
        idRes: Int?,
        createBindingListener: ((ViewDataBinding) -> Unit)?,
        bindDataListener: ((ViewDataBinding) -> Unit)?
    ) {
        if (idRes != null) {
            headLayoutIdRes = idRes
            headCreateBindingListener = createBindingListener
            headBindViewListener = bindDataListener
        }
    }

    fun setFootLayout(
        idRes: Int?,
        createBindingListener: ((ViewDataBinding) -> Unit)?,
        bindDataListener: ((ViewDataBinding) -> Unit)?
    ) {
        if (idRes != null) {
            footLayoutIdRes = idRes
            footCreateBindingListener = createBindingListener
            footBindViewListener = bindDataListener
        }
    }

    fun setEmptyLayout(
        idRes: Int?,
        createBindingListener: ((ViewDataBinding) -> Unit)?,
        bindDataListener: ((ViewDataBinding) -> Unit)?
    ) {
        if (idRes != null) {
            emptyLayoutIdRes = idRes
            emptyCreateBindingListener = createBindingListener
            emptyBindViewListener = bindDataListener
        }
    }

    //只有IdRes不为空时，其他布局才能生效
    override fun getItemViewType(position: Int): Int {
        return if (dataList.size == 0 && emptyLayoutIdRes != null && position == 0) {
            emptyViewType
        } else {
            when (position) {
                0 -> if (headLayoutIdRes != null) headViewType else contentViewType
                dataList.size + if (headLayoutIdRes != null) 1 else 0 -> if (footLayoutIdRes != null) footViewType else contentViewType
                else -> contentViewType
            }
        }
    }

    override fun getItemCount(): Int {
        return if (dataList.size == 0 && emptyLayoutIdRes != null) {
            1
        } else {
            dataList.size + (if (headLayoutIdRes != null) 1 else 0) + (if (footLayoutIdRes != null) 1 else 0)
        }
    }

    //RecyclerView的Attach过程
    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        dataList.addOnListChangedCallback(listChangedCallback)
    }

    //RecyclerView的Detach过程
    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        dataList.removeOnListChangedCallback(listChangedCallback)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            headViewType -> {
                val binding = DataBindingUtil.inflate<ViewDataBinding>(
                    LayoutInflater.from(context),
                    headLayoutIdRes!!,
                    parent,
                    false
                )
                headCreateBindingListener?.run {
                    this(binding)
                }
                HeadDataBindingRecyclerViewHolder(binding)
            }
            footViewType -> {
                val binding = DataBindingUtil.inflate<ViewDataBinding>(
                    LayoutInflater.from(context),
                    footLayoutIdRes!!,
                    parent,
                    false
                )
                footCreateBindingListener?.run {
                    this(binding)
                }
                FootDataBindingRecyclerViewHolder(binding)
            }
            emptyViewType -> {
                val binding = DataBindingUtil.inflate<ViewDataBinding>(
                    LayoutInflater.from(context),
                    emptyLayoutIdRes!!,
                    parent,
                    false
                )
                emptyCreateBindingListener?.run {
                    this(binding)
                }
                EmptyDataBindingRecyclerViewHolder(binding)
            }
            else -> {
                val binding = DataBindingUtil.inflate<ViewDataBinding>(
                    LayoutInflater.from(context),
                    getContentLayoutResId(),
                    parent,
                    false
                )
                setContentViewHolderCreateListener(binding)
                ContentDataBindingRecyclerViewHolder(binding)
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (position == RecyclerView.NO_POSITION) return
        when (holder) {
            is HeadDataBindingRecyclerViewHolder -> {
                headBindViewListener?.run {
                    this(holder.binding)
                }
            }
            is FootDataBindingRecyclerViewHolder -> {
                footBindViewListener?.run {
                    this(holder.binding)
                }
            }
            is EmptyDataBindingRecyclerViewHolder -> {
                emptyBindViewListener?.run {
                    this(holder.binding)
                }
            }
            is ContentDataBindingRecyclerViewHolder -> {
                val dataPosition = holder.adapterPosition - if (headLayoutIdRes != null) 1 else 0
                setContentViewHolderBindListener(holder.binding, dataPosition)
            }
        }
    }

    override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
        super.onViewRecycled(holder)
    }

}

class ContentDataBindingRecyclerViewHolder(val binding: ViewDataBinding) :
    RecyclerView.ViewHolder(binding.root)

class HeadDataBindingRecyclerViewHolder(val binding: ViewDataBinding) :
    RecyclerView.ViewHolder(binding.root)

class FootDataBindingRecyclerViewHolder(val binding: ViewDataBinding) :
    RecyclerView.ViewHolder(binding.root)

class EmptyDataBindingRecyclerViewHolder(val binding: ViewDataBinding) :
    RecyclerView.ViewHolder(binding.root)

fun <T> ObservableArrayList<T>.removeRange(fromIndex: Int, toIndex: Int) {
    val clazz = this::class.java
    val method = clazz.getDeclaredMethod("removeRange", Int::class.java, Int::class.java)
    method.isAccessible = true
    method.invoke(this, fromIndex, toIndex)
}

fun <T> ObservableArrayList<T>.clearAndAddAll(collection: Collection<out T>) {
    (this as ArrayList<T>).clear()
    this.addAll(collection)
}
